#include <UI/UILabel.h>
#include <UI/UIWindow.h>
#include <UI/UIManager.h>

namespace ne
{
    UILabel::UILabel(const std::string &name)
        : UIObject(name),
          mTextColor(UI_COLOR_WHITE),
          mFontLayout(FL_LEFT_TO_RIGHT),
          mTextOffset(0.0f),
          mNeedTextUpdate(false)
    {
    }

    // Color
    void UILabel::setTextColor(const Color &color)
    {
        mTextColor = color;
    }

    Color UILabel::getTextColor() const
    {
        return mTextColor;
    }

    void UILabel::setTextAlpha(const real alpha)
    {
        mTextColor.a = alpha;
    }

    real UILabel::getTextAlpha() const
    {
        return mTextColor.a;
    }

    void UILabel::setFontLayout(const FontLayout layout)
    {
        if (mFontLayout != layout)
        {
            mFontLayout = layout;
            needTextUpdate();
        }
    }

    FontLayout UILabel::getFontLayout() const
    {
        return mFontLayout;
    }

    void UILabel::setText(const std::string &text)
    {
        mText = text;
    }

    void UILabel::setText(const Unicode &text)
    {
        mText = text;
    }

    const Unicode& UILabel::getText() const
    {
        return mText;
    }

    void UILabel::needTextUpdate()
    {
        mNeedTextUpdate = true;
    }

    void UILabel::updateText(const bool forceUpdate)
    {
        if (mNeedTextUpdate || forceUpdate)
        {
            mTextOffset = 0.0f;
            UIWindow *pWindow = getWindow();
            if (pWindow)
            {
                FontPtr pFont = pWindow->getFont();
                if (pFont.notNull())
                {
                    const Unicode &text = getText();
                    size_t length = text.length();
                    if (length > 0)
                    {
                        FontLayout layout = getFontLayout();
                        real defaultOffset = pFont->getDefaultGlyphOffset(layout);
                        for (size_t i=0; i<length; ++i)
                        {
                            real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                            mTextOffset += (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;
                        }
                    }
                }
            }
        }
    }

    UILabel::~UILabel()
    {
    }

    bool UILabel::_updateSelf()
    {
        if (UIObject::_updateSelf())
        {
            updateText();
            return true;
        }
        return false;
    }

    bool UILabel::_renderSelf()
    {
        if (UIObject::_renderSelf())
        {
            UIWindow *pWindow = getWindow();
            if (pWindow)
            {
                _genFontGeometry(pWindow->getFontGeometry(), pWindow->getFont());
            }
            return true;
        }       
        return false;
    }

    void UILabel::_genFontGeometry(const DynamicGeometryPtr &pGeometry, const FontPtr &pFont)
    {
        if (pGeometry.notNull() && pFont.notNull())
        {
            UIWindow *pWindow = getWindow();
            if (pWindow)
            {
                FontPtr pFont = pWindow->getFont();
                if (pFont.notNull())
                {
                    const Unicode &text = getText();
                    size_t length = text.length();
                    if (length > 0)
                    {
                        updateText();

                        FontLayout layout = getFontLayout();
                        real defaultOffset = pFont->getDefaultGlyphOffset(layout);
                        Vector3 pos = getAlignPosition();
                        Vector3 xAxis = getXAxis();
                        Vector3 yAxis = getYAxis();
                        real width = getWidth();
                        real height = getHeight();
                        Color color = getTextColor();
                        switch (layout)
                        {
                            case FL_LEFT_TO_RIGHT:
                            {
                                real offset = 0.0f;
                                pos += yAxis * height * 0.5f;
                                size_t i = 0;
                                while (i<length)
                                {
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    offset += (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;

                                    if (offset > width) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        pos += xAxis * glyphOffset;
                                    }
                                    else
                                    {
                                        pos += xAxis * defaultOffset;
                                    }
                                    ++i;
                                }
                                break;
                            }

                            case FL_RIGHT_TO_LEFT:
                            {
                                real offset = 0.0f;
                                pos += xAxis * width + yAxis * height * 0.5f;
                                size_t i = length;
                                do
                                {
                                    --i;
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    offset += (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;

                                    if (offset > width) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        pos -= xAxis * glyphOffset;
                                    }
                                    else
                                    {
                                        pos -= xAxis * defaultOffset;
                                    }
                                } while (i > 0);
                                break;
                            }

                            case FL_TOP_TO_BOTTOM:
                            {
                                real offset = 0.0f;
                                pos += xAxis * width * 0.5f + yAxis * height;
                                size_t i = 0;
                                while (i<length)
                                {
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    offset += (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;

                                    if (offset > height) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        pos -= yAxis * glyphOffset;
                                    }
                                    else
                                    {
                                        pos -= yAxis * defaultOffset;
                                    }
                                    ++i;
                                }
                                break;
                            }

                            case FL_BOTTOM_TO_TOP:
                            {
                                real offset = 0.0f;
                                pos += xAxis * width * 0.5f;
                                size_t i = length;
                                do
                                {
                                    --i;
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    offset += (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;

                                    if (offset > height) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        pos += yAxis * glyphOffset;
                                    }
                                    else
                                    {
                                        pos += yAxis * defaultOffset;
                                    }
                                } while (i > 0);
                                break;
                            }

                            case FL_HORIZONTAL:
                            {
                                real offset = (width - mTextOffset) * 0.5f;
                                pos += xAxis * (width - mTextOffset) * 0.5f + yAxis * height * 0.5f;
                                size_t i = 0;
                                while (i<length)
                                {
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    real curGlyphOffset = (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;
                                    offset += curGlyphOffset;

                                    if (offset > width) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        if (offset - curGlyphOffset >= 0.0f)
                                        {
                                            pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        }
                                    }
                                    pos += xAxis * curGlyphOffset;
                                    ++i;
                                }
                                break;
                            }

                            case FL_VERTICAL:
                            {
                                real offset = (height - mTextOffset) * 0.5f;
                                pos += xAxis * width * 0.5f + yAxis * (height + mTextOffset) * 0.5f;
                                size_t i = 0;
                                while (i<length)
                                {
                                    real glyphOffset = pFont->getGlyphOffset(text[i], layout);
                                    real curGlyphOffset = (glyphOffset > 0.0f) ? glyphOffset : defaultOffset;
                                    offset += curGlyphOffset;

                                    if (offset > height) break;

                                    if (glyphOffset > 0.0f)
                                    {
                                        if (offset - curGlyphOffset >= 0.0f)
                                        {
                                            pFont->genGlyphGeometry(text[i], pGeometry, pos, xAxis, yAxis, color, layout);
                                        }
                                    }
                                    pos -= yAxis * curGlyphOffset;
                                    ++i;
                                }
                                break;
                            }

                            default: break;
                        }
                    }
                }
            }
        }
    }

}
